<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="" />
<meta name="author" content="Maxim Sokhatsky" />
<title>BERT.JS</title>
<link rel="stylesheet" href="https://n2o.dev/blank.css?x=15" />
<link rel="stylesheet" href="https://n2o.dev/zima.css?x=15" />
<link rel="shortcut icon" type="image/x-icon" href="../img/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="../img/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="../img/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="../img/favicon-16x16.png" />
<link rel="manifest" href="../img/site.webmanifest" />
</head>
<body>
<nav>
  <a href="https://n2o.dev">DEV</a>
  <a href="https://ws.n2o.dev">N2O</a>
  <a href="#" style="background:#ededed;">BERT.JS</a>
  <div class="dropdown">
    <a onclick="drop()" class="dropbtn">EN</a>
    <div id="dropdown" class="dropdown-content">
      <a href="https://n2o.dev/ua/deps/n2o/man/bert.js.htm">UA</a>
      <a href="bert.js.htm">EN</a>
    </div>
  </div>
</nav>
<header>
  <a href="../index.html"><img src="https://openmoji.org/data/color/svg/2B55.svg" /></a>
  <h1>BERT.JS</h1>
</header>
<main>
<article>
  <section>
    <h3>INTRO</h3>
    <p>The <a href="https://github.com/synrc/n2o/blob/master/priv/bert.js">bert.js</a>
      module provides JavaScript encoder/decoder for
      <a href="http://erlang.org/doc/apps/erts/erl_ext_dist.html">External Term Format</a>
      used in Erlang distribution protocol. That means
      your JavaScript applications talk to Erlang natively. This module
      uses <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView">DataView</a>
      and <b>getUint8</b>, <b>getUint16</b>, <b>getUint32</b> word accessors which is
      the fastest way of dealing with binaries in JavaScript.
      The library is used in Erang and Haskell N2O versions.
      The size of <b>bert.js</b> is 4654 bytes.</p>
    <p>Note that this library is low-level, fast version
       of BERT encoder/decoder. If you want to generate
       JavaScript SDK with field names as in Erlang include
       files, please take <a href="https://rpc.n2o.dev">RPC</a>
       as high-level counterpart library that generates
       wrappers around <b>bert.js</b> and provides
       more slick JavaScript experience.</p>
    <p>Erlang structure that compiles to BERT format:</p>
    <figure>
      <code>
  #io{ code = login,
       data = { 'Token', 42 } }
      </code>
    </figure>
    <p>Target structure of <a href="#">bert.js</a> — fast low-level handcoded parser from BERT format.</p>
    <figure>
      <code>
  { t: 104,
    v: [ { t: 100, v: "io" },
     { t: 100, v: "login" },
     { t: 104, v: [ { t: 100, v: "Token" },
                    { t: 97,  v: 42 } ] } ] }
      </code>
    </figure>
    <p>Target structure of generated parser with <a href="https://rpc.n2o.dev">RPC</a> parse transform:</p>
    <figure>
      <code>
  { tup: 'io',
    code: 'login',
    data: { tup: '$',
              0: 'Token',
              1: 42 } },
      </code>
    </figure>
  </section>
  <section>
    <p>The following practical subset of BERT format is supported:</p>
  </section>
  <section>
    <h3>70</h3>
    <p>IEEE-754 float encoding. A float is stored as 8 bytes in big-endian IEEE format.
       This term is used in minor version 1 of the external format.</p>
    <figure>
      <code>
  1     8
  70    IEEE-754 float
      </code>
    </figure>
  </section>
  <section>
    <h3>97</h3>
    <p>Byte encoding. Unsigned 8-bit integer.</p>
    <figure>
      <code>
  1     1
  97    Int
      </code>
    </figure>
  </section>
  <section>
    <h3>98</h3>
    <p>Integer encoding. Signed 32-bit integer in big-endian format.</p>
    <figure>
      <code>
  1     4
  98    Int
      </code>
    </figure>
  </section>
  <section>
    <h3>99</h3>
    <p>Float POSIX encoding. A float is stored in string format. The format used
       in sprintf to format the float is "%.20e" (there are more bytes
       allocated than necessary). To unpack the float, use sscanf with format "%lf".
       </p>
    <figure>
      <code>
  1     31
  99    Float POSIX string.
      </code>
    </figure>
  </section>
  <section>
    <h3>100</h3>
    <p>Atom encoding. An atom is stored with a 2 byte unsigned length in big-endian order,
       followed by N numbers of 8-bit Latin-1 characters that forms the name.
       The maximum allowed value for Len is 255.</p>
    <figure>
      <code>
  1    2  N
  100  N  Characters
      </code>
    </figure>
  </section>
  <section>
    <h3>104</h3>
    <p>Tuple encoding. The Arity field is an unsigned byte N that determines
       how many elements that follows in section Elements.</p>
    <figure>
      <code>
  1    1  N
  104  N  Elements
      </code>
    </figure>
  </section>
  <section>
    <h3>105</h3>
    <p>Large tuple encoding. Same as 104 except that N is an unsigned 4
       byte integer in big-endian format.</p>
    <figure>
      <code>
  1    4  N
  105  N  Elements
      </code>
    </figure>
  </section>
  <section>
    <h3>106</h3>
    <p>Nil.</p>
    <figure>
      <code>
  1
  106
      </code>
    </figure>
  </section>
  <section>
    <h3>107</h3>
    <p>String encoding. As field N is an unsigned 2
       byte integer (big-endian), implementations must ensure that lists longer
       than 65535 elements are encoded as 108.
    </p>
    <figure>
      <code>
  1    2  N
  107  N  Characters
      </code>
    </figure>
  </section>
  <section>
    <h3>108</h3>
    <p>List encoding. N is the number of elements that follows in section Characters.
       Tail is the final tail of the list; it is 106 for a proper list,
       but can be any type if the list is improper (for example, [a|b]).
    </p>
    <figure>
      <code>
  1    4  N
  108  N  Characters  Tail
      </code>
    </figure>
  </section>
  <section>
    <h3>109</h3>
    <p>Binary encoding. Binaries are generated with bit syntax expression or with
       erlang:list_to_binary/1, erlang:term_to_binary/1, or as
       input from binary ports. The N length field is an unsigned
       4 byte integer (big-endian).
    </p>
    <figure>
      <code>
  1    4  N
  109  N  Bytes
      </code>
    </figure>
  </section>
  <section>
    <h3>110</h3>
    <p>Small bignum encoding. Bignums are stored in unary form with a Sign byte, that is,
       0 if the binum is positive and 1 if it is negative.
       The digits are stored with the least significant byte stored first.
       To calculate the integer, the following formula can be used:</p>
    <figure>
      <code>
  1    1  1  n
  110  n  Sign d(0)...d(n-1)
      </code>
    </figure>
    <p>
   B = 256,<br />
   d<sub>0</sub>*B<sup>0</sup>
   + d<sub>1</sub>*B<sup>1</sup>
   + d<sub>2</sub>*B<sup>2</sup>
   + ... d<sub>N-1</sub>*B<sup>(n-1)</sup>
    </p>
  </section>
  <section>
    <h3>111</h3>
    <p>Large bignum encoding.
       Same as 110 except that the length field is an unsigned 4 byte integer.</p>
    <figure>
      <code>
    1  4  1  n
  111  n  Sign d(0)...d(n-1)
      </code>
    </figure>
  </section>
  <section>
    <h3>115</h3>
    <p>Small atom encoding. An atom is stored with a 1 byte unsigned
       length, followed by N numbers of 8-bit Latin-1 characters
       that forms the Characters.
    </p>
    <figure>
      <code>
    1  1  N
  115  N  Characters
      </code>
    </figure>
  </section>
  <section>
    <h3>116</h3>
    <p>Maps encoding. The N field is an unsigned 4 byte integer
       in big-endian format that determines the number of key-value
       pairs in the map. Key and value pairs (Ki => Vi) are encoded
       in section Pairs in the following order: K1, V1, K2, V2,...,
       Kn, Vn. Duplicate keys are not allowed within the same map.
       Requires OTP 17.
    </p>
    <figure>
      <code>
    1  4  N
  116  N  K1,V1,K2,V2,...
      </code>
    </figure>
  </section>
  <section>
    <h3>118</h3>
    <p>UTF8 atom encoding. An atom is stored with a 2 byte unsigned
       length in big-endian order, followed by N bytes containing
       the Characters encoded in UTF-8.
    </p>
    <figure>
      <code>
    1  2  N
  118  N  Characters
      </code>
    </figure>
  </section>
  <section>
    <h3>119</h3>
    <p>UTF8 small atom encoding. An atom is stored with a 1 byte unsigned
       length, followed by N bytes containing the Characters encoded in UTF-8.
       Longer atoms encoded in UTF-8 can be represented using 118.
    </p>
    <figure>
      <code>
    1  1  N
  119  N  Characters
      </code>
    </figure>
  </section>
  <section>
    <h3>API</h3>
    <h4>enc(json)</h4>
    <p>Encodes internal JSON to binary buffer.</p>
    <figure>
      <code>
  > enc({t: 119, v: "日本"})

  Uint8Array([131,119,6,230,151,165,230,156,172])
      </code>
    </figure>
    <h4>dec(buffer)</h4>
    <p>Decodes binary buffer to internal JSON.</p>
    <figure>
      <code>
  > dec((new Uint8Array([131,119,6,230,151,165,230,156,172])).buffer)

  {t: 119, v: "日本"}
      </code>
    </figure>
    <h4>bin(x)</h4>
    <figure>
      <code>
  > dec(enc(bin('N2O,')).buffer))

  {t: 109, v: "N2O,"}

  [131,109,0,0,0,4,78,50,79,44]
      </code>
    </figure>
    <p>Creates JSON for binary encoding.</p>
    <h4>atom(x)</h4>
    <p>Creates JSON for Latin-1 atom encoding.</p>
    <figure>
      <code>
  > dec(enc(atom('ok')).buffer))

  {t: 100, v: "ok"}

  [131,100,0,2,111,107]
      </code>
    </figure>
    <h4>string(x)</h4>
    <p>Creates JSON for string encoding.</p>
    <figure>
      <code>
  > dec(enc(string('ok')).buffer))

  {t: 107, v: "ok"}

  [131,107,0,2,111,107]
      </code>
    </figure>
    <h4>float(x)</h4>
    <p>Creates JSON for IEEE-754 float encoding.</p>
    <figure>
      <code>
  > dec(enc(float('123.13')).buffer)

  {t: 70, v: 123.13}

  [131,70,64,94,200,81,235,133,30,184]
      </code>
    </figure>
    <h4>number(x)</h4>
    <p>Creates JSON for integers and GMP big numbers encoding.</p>
    <figure>
      <code>
  > dec(enc(number('1')).buffer)

  {t: 97, v: 1}

  [131,97,1]

  > dec(enc(number('100000000')).buffer)
  {t: 98, v: 100000000}

  [131,98,5,245,225,0]

  > dec(enc(number('10000000000000000000000')).buffer)

  {t: 110, v: 1e+22}

  [131,110,10,0,0,0,64,178,186,201,224,25,30,2]
      </code>
    </figure>
    <h4>list(x,...)</h4>
    <p>Creates JSON for list encoding.</p>
    <figure>
      <code>
  > dec(enc(list(atom('1'),number('1'),bin('1'))).buffer)

  {t: 108, v: [{t: 100, v: "1"},
               {t: 97, v: 1},
               {t: 109, v: "1"}]}

  [131,108,0,0,0,3,100,0,1,49,97,1,109,0,0,0,1,49,106]
      </code>
    </figure>
    <h4>tuple(x,...)</h4>
    <p>Creates JSON for tuple encoding.</p>
    <figure>
      <code>
  > dec(enc(tuple(atom('1'),number('1'),bin('1'))).buffer)

  {t: 104, v: [{t: 100, v: "1"},
               {t: 97, v: 1},
               {t: 109, v: "1"}]}

  [131,104,3,100,0,1,49,97,1,109,0,0,0,1,49]
      </code>
    </figure>
    <h4>map(x,...)</h4>
    <p>Creates JSON for map encoding.</p>
    <figure>
      <code>
  > dec(enc(map(
      {k:bin('rent'),v:float(1.2)},
      {k:atom('ok'), v:list(number(1),float(1.0),bin('1'))})).buffer)

  {t:116, v:[{k:{t:109,v:"rent"},v:{t:70, v:1.2}},
             {k:{t:100,v:"ok"},  v:{t:108,v:[{t:97, v:1},
                                             {t:70, v:1},
                                             {t:109,v:"1"}]}}]}

  [131,116,0,0,0,2,109,0,0,0,4,114,101,110,
   116,70,63,243,51,51,51,51,51,51,100,0,2,
   111,107,108,0,0,0,3,97,1,70,63,240,0,0,0,
   0,0,0,109,0,0,0,1,49,106]
      </code>
    </figure>
  </section>
  <section>
    <p>You may also want to read:
      <a href="utf8.js.htm">utf8.js</a>,
      <a href="ieee754.js.htm">ieee754.js</a>,
      <a href="heart.js.htm">heart.js</a>,
      <a href="nitro.js.htm">nitro.js</a>,
      <a href="mq.js.htm">mq.js</a>,
      <a href="n2o.js.htm">n2o.js</a>.
    </p>
  </section>
</article>
</main>
<footer>2005—2020 © Synrc Research Center</footer>
<script>function drop(){document.getElementById("dropdown").classList.toggle("show");}</script>
</body>
</html>
